import numpy as np


class RunningModel:
    def __init__(self, master):
        self.master = master
        # 配合model所需字段
        self.data_len = None
        self.point_num = None
        self.group_size = None

        self.canvas_data_ls = []
        self.ori_draw_data = []
        self.final_draw_data_x = []
        self.final_draw_data_y = []
        # 初始化日志引擎
        self.log_engine = None
        self.px_unit = 5  # n个像素为一个绘制单元
        # canvas配置
        self.net_value_area = [0, 1]
        self.close_area = [0, 1]
        self.factor_area = [0, 0.3]

    def sec_init(self):
        self.point_num = self.master.main_window_view.running_view.canvas.winfo_width() // self.px_unit
        pass

    def set_data_len(self, data_len):
        self.data_len = data_len

    def reset(self):
        self.point_num = self.master.main_window_view.running_view.canvas.winfo_width() // self.px_unit
        self.group_size = self.data_len // self.point_num + 1
        # 传入了净值数据和收盘价数据
        self.master.main_window_view.running_view.draw(self.final_draw_data_x, self.final_draw_data_y)
        pass

    def refresh(self):
        # 传入了净值数据和收盘价数据
        self.master.main_window_view.running_view.draw(self.final_draw_data_x, self.final_draw_data_y)
        pass

    def on_canvas_data(self, canvas_data: list):
        if self.data_len is None:
            raise ValueError("Running类未设置数据长度及其相关属性！")
        elif self.group_size is None:
            # 初次运行，完善关键参数
            self.point_num = self.master.main_window_view.running_view.canvas.winfo_width() // self.px_unit
            self.group_size = self.data_len // self.point_num + 1
        if not isinstance(canvas_data, list):
            raise ValueError("canvas data元素数据不为列表。")
        self.canvas_data_ls.append(canvas_data)
        self.gen_draw_data()

    def config_log_engine(self):
        self.log_engine = self.master.file_manager.log_engine

    def gen_draw_data(self):
        # 获取当前canvas窗口的高度
        canvas_width = self.master.main_window_view.running_view.canvas.winfo_width()
        canvas_height = self.master.main_window_view.running_view.canvas.winfo_height()-4
        # 将原始数据转为实际绘制数据
        # 数据注解：canvas data实际最多包含三个元素，第一个为净值数据列表，形如[122, 221]代表本节点有两个净值数据，
        # 第二个为收盘价数据列表，形如[23.44, 225.32]代表本节点有两个收盘价数据，多个品种
        # 第三个为关键因子数据列表，形如[0.823, 253.9]代表本节点有两个因子数据，（具体对应关系由策略逻辑确定）
        canvas_data_len = len(self.canvas_data_ls)
        if canvas_data_len % self.group_size == 0:
            draw_data_o = self.canvas_data_ls[-1]

            self.ori_draw_data.append(draw_data_o)

            # 对draw_data进行缩放处理，使呈现的画面更美观。
            final_draw_data = np.array(self.ori_draw_data)
            final_draw_data[:, 0] /= self.ori_draw_data[0][0]
            final_draw_data[:, 1] /= self.ori_draw_data[0][1]
            # 进一步缩放使得净值和收盘价数据以合理形式呈现
            # 控制净值（序列0）

            self.final_draw_data_x = [i*self.px_unit for i in range(len(self.ori_draw_data))]
            # 缩放draw_data的数据，第一个值统一

            net_value_close_max_min = [np.max(final_draw_data), np.min(final_draw_data)]
            if net_value_close_max_min[0] - net_value_close_max_min[1] != 0:
                net_value_close_rate = canvas_height / (net_value_close_max_min[0] - net_value_close_max_min[1])
            else:
                net_value_close_rate = 0
            draw_data_y_arr = canvas_height - (final_draw_data - net_value_close_max_min[1]) * net_value_close_rate
            self.final_draw_data_y = draw_data_y_arr.tolist()
            self.refresh()

    def canvas_init(self):
        # 清空canvas
        self.master.main_window_view.running_view.del_canvas()
        # 还原model中相关数据
        # 配合model所需字段
        self.data_len = None
        self.point_num = None
        self.group_size = None

        self.canvas_data_ls = []
        self.ori_draw_data = []
        self.final_draw_data_x = []
        self.final_draw_data_y = []

        self.point_num = self.master.main_window_view.running_view.canvas.winfo_width() // self.px_unit

